package com.h2.ref.server.web.user.account.settings;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.h2.ref.server.auth.AuthUtils;
import com.h2.ref.server.user.IUserService;
import com.h2.ref.server.user.UserPasswordProvider;
import com.h2.ref.server.user.model.User;
import com.h2.ref.server.user.model.UserDetails;
import com.h2.ref.server.web.ViewConstants;
import com.h2.ref.server.web.user.UserValidator;
import com.h2.ref.server.web.user.account.UserActivationController;

@Controller
public class UserSettingsController {
   
   protected static final Logger LOG =
         LoggerFactory.getLogger(UserSettingsController.class);
   
   /////
   
   private static final String USER_MODEL = "user";
   
   ////
   
   private IUserService _userService;
   
   private UserActivationController _userActivationController;
   
   private UserPasswordProvider _userPasswordProvider;
   
   private Boolean _emailActivation = Boolean.TRUE;
   
   ////
   ////
   
   @RequestMapping(value=ViewConstants.SETTINGS_GENERAL, method=RequestMethod.GET)
   public String show(Model model) {
      User user = getUserService().getActiveUser(false);
      model.addAttribute(USER_MODEL, user);
      
      return ViewConstants.SETTINGS_VIEW;
   }
   
   @RequestMapping(value=ViewConstants.SETTINGS_UPDATE_PASSWORD,
         method=RequestMethod.GET)
   public ModelAndView showUserPassword() {
      ModelAndView modelView = new ModelAndView(
            ViewConstants.SETTINGS_UPDATE_PASSWORD_VIEW);
      modelView.addObject(USER_MODEL, new PasswordUpdateUser());
      return modelView;
   }
   
   /**
    * TODO_DOCUMENT_ME
    *
    * @param model
    * @param user
    * @param binding
    * @return
    * @since 
    */
   @RequestMapping(value=ViewConstants.SETTINGS_UPDATE_PASSWORD,
         method=RequestMethod.POST)
   public String updateUserPassword(
         @ModelAttribute(USER_MODEL) PasswordUpdateUser user,
         BindingResult binding) {
      
      User currentUser = getUserService().getActiveUser();
      UserValidator.validatePassword(user.getPassword(), binding);
      if (!currentUser.getPassword().equals(
            getUserPasswordProvider().encrypt(user.getPasswordOld()))) {
         binding.rejectValue("passwordConfirm",
               "register.password.passwordConfirm");
      }
      
      if (binding.hasErrors()) {
         return ViewConstants.SETTINGS_UPDATE_PASSWORD_VIEW;
      }
      else {
         User updateUser = new User();
         updateUser.setId(currentUser.getId());
         updateUser.setPassword(user.getPassword());
         getUserService().update(user);
         
         AuthUtils.changeAuth(currentUser.getName(),
               user.getPassword());
         
         return ViewConstants.REDIRECT
               + ViewConstants.SETTINGS_GENERAL + ".html";
      }
   }
   
   
   @RequestMapping(value=ViewConstants.SETTINGS_UPDATE_NAME,
         method=RequestMethod.GET)
   public ModelAndView showUserName() {
      ModelAndView modelView = new ModelAndView(
            ViewConstants.SETTINGS_UPDATE_NAME_VIEW);
      User currentUser = getUserService().getActiveUser();
      User user = new User();
      user.setName(currentUser.getName());
      modelView.addObject(USER_MODEL, user);
      return modelView;
   }
   
   @RequestMapping(value=ViewConstants.SETTINGS_UPDATE_NAME,
         method=RequestMethod.POST)
   public String updateUserName(
         @ModelAttribute(USER_MODEL) User user,
         BindingResult binding) {
      
      User currentUser = getUserService().getActiveUser();
      
      UserValidator.validateName(user.getName(), binding);
      UserValidator.validatePassword(user.getPassword(), binding);
      if (!currentUser.getPassword().equals(
            getUserPasswordProvider().encrypt(user.getPassword()))) {
         binding.rejectValue("password",
               "AbstractUserDetailsAuthenticationProvider.badCredentials");
      }
      
      if (binding.hasErrors()) {
         return ViewConstants.SETTINGS_UPDATE_NAME_VIEW;
      }
      else if (currentUser.getName().equals(user.getName())) {
         return ViewConstants.SETTINGS_UPDATE_NAME_VIEW;
      }
      else {
         User updateUser = new User();
         updateUser.setId(currentUser.getId());
         updateUser.setName(user.getName());
         getUserService().update(updateUser);
         
         AuthUtils.changeAuth(user.getName(),
               currentUser.getPassword());
         
         return ViewConstants.REDIRECT
               + ViewConstants.SETTINGS_GENERAL + ".html";
      }
   }
   
   @RequestMapping(value=ViewConstants.SETTINGS_UPDATE_EMAIL,
         method=RequestMethod.GET)
   public ModelAndView showUserEmail() {
      ModelAndView modelView = new ModelAndView(
            ViewConstants.SETTINGS_UPDATE_EMAIL_VIEW);
      User currentUser = getUserService().getActiveUser();
      User user = new User();
      user.setUserDetails(new UserDetails());
      user.getUserDetails().setEmail(currentUser.getUserDetails().getEmail());
      modelView.addObject(USER_MODEL, user);
      return modelView;
   }
   
   @RequestMapping(value=ViewConstants.SETTINGS_UPDATE_EMAIL,
         method=RequestMethod.POST)
   public String updateUserEmail(
         @ModelAttribute(USER_MODEL) User user,
         BindingResult binding) {
      
      User currentUser = getUserService().getActiveUser();
      
      UserValidator.validateEmail(user.getUserDetails().getEmail(), binding);
      UserValidator.validatePassword(user.getPassword(), binding);
      if (binding.hasErrors()) {
         return ViewConstants.SETTINGS_UPDATE_EMAIL_VIEW;
      }
      else if (currentUser.getUserDetails().getEmail().equals(
            user.getUserDetails().getEmail())) {
         return ViewConstants.SETTINGS_UPDATE_EMAIL_VIEW;
      }
      else {
         User updateUser = new User();
         updateUser.setUserDetails(new UserDetails());
         updateUser.setId(currentUser.getId());
         updateUser.getUserDetails().setEmail(user.getUserDetails().getEmail());
         
         //don't change email if something bad happens to email
         if (getEmailActivation()) {
            if(!getUserActivationController().sendActivationEmail(currentUser)) {
               binding.rejectValue("userDetails.email",
                     "register.email.invalid.error");
               return ViewConstants.SETTINGS_UPDATE_EMAIL_VIEW;
            }
            updateUser.setActive(false);
         }
         getUserService().update(updateUser);
         
         return ViewConstants.REDIRECT
               + ViewConstants.ACCOUNT_EMAIL_SEND_ACTIVATE + ".html";
      }
   }
   
   @RequestMapping(value=ViewConstants.ACCOUNT_DELETE,
         method=RequestMethod.GET)
   public String deleteAccount() {
      User user = getUserService().getActiveUser();
      getUserService().delete(user);
      return ViewConstants.REDIRECT + ViewConstants.SIGNOUT;
   }
   
   public static class PasswordUpdateUser extends User {
      private String _passwordOld;
      
      ////
      ////

      /**
       * @return the passwordOld
       */
      public String getPasswordOld() {
         return _passwordOld;
      }

      /**
       * @param passwordOld the passwordOld to set
       */
      public void setPasswordOld(String passwordOld) {
         _passwordOld = passwordOld;
      }
   }

   /**
    * @return the emailActivation
    */
   public Boolean getEmailActivation() {
      return _emailActivation;
   }

   /**
    * @param emailActivation the emailActivation to set
    */
   public void setEmailActivation(Boolean emailActivation) {
      _emailActivation = emailActivation;
   }

   /**
    * @return the userService
    */
   public IUserService getUserService() {
      return _userService;
   }

   /**
    * @param userService the userService to set
    */
   public void setUserService(IUserService userService) {
      _userService = userService;
   }

   /**
    * @return the userActivationController
    */
   public UserActivationController getUserActivationController() {
      return _userActivationController;
   }

   /**
    * @param userActivationController the userActivationController to set
    */
   public void setUserActivationController(
         UserActivationController userActivationController) {
      _userActivationController = userActivationController;
   }

   /**
    * @return the userPasswordProvider
    */
   public UserPasswordProvider getUserPasswordProvider() {
      return _userPasswordProvider;
   }

   /**
    * @param userPasswordProvider the userPasswordProvider to set
    */
   public void setUserPasswordProvider(UserPasswordProvider userPasswordProvider) {
      _userPasswordProvider = userPasswordProvider;
   }
   
}
